package com.wuzuqing.android.eightdiagrams.utils

import android.app.Dialog
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.PopupWindow
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty

/**
 * Created by coud on 2022/6/14.
 */

inline fun  <reified VB: ViewBinding> AppCompatActivity.binding(crossinline inflater: (LayoutInflater) -> VB) =
    lazy(LazyThreadSafetyMode.NONE) {
    inflater(layoutInflater).also {
        setContentView(it.root)
    }
}

inline fun <reified VB: ViewBinding> Fragment.binding(noinline bind: (View) -> VB) = FragmentBindingDelegate(bind)

inline fun <reified VB: ViewBinding> View.binding(crossinline inflater: (LayoutInflater, ViewGroup, Boolean) -> VB) = lazy(LazyThreadSafetyMode.NONE) {
    inflater(LayoutInflater.from(this.context), this as ViewGroup, true)
}

inline fun <VB: ViewBinding> View.getBinding(bind: (View) -> VB): VB = bind(this)

class FragmentBindingDelegate<VB: ViewBinding>(private val bind: (View) -> VB) : ReadOnlyProperty<Fragment, VB> {

    private var mBinding: VB? = null

    override fun getValue(thisRef: Fragment, property: KProperty<*>): VB {
        mBinding = try {
            thisRef.requireView().getBinding(bind).also { binding ->
//                if (binding is ViewDataBinding) binding.lifecycleOwner = thisRef.viewLifecycleOwner
            }
        }catch (e: IllegalStateException) {
            throw IllegalStateException("The property of ${property.name} has been destroyed.")
        }
        val observer = LifecycleEventObserver { _, event ->
            when(event) {
                Lifecycle.Event.ON_DESTROY -> {
                    mBinding = null
                }
                else -> {}
            }
        }
        thisRef.viewLifecycleOwner.lifecycle.addObserver(observer)
        return mBinding!!
    }
}

inline fun <VB: ViewBinding> BindingViewHolder<VB>.withBinding(block: VB.(BindingViewHolder<VB>) -> Unit) = apply {
    block(binding, this)
}

open class BindingViewHolder<VB: ViewBinding>(val binding: VB) : RecyclerView.ViewHolder(binding.root) {
    constructor(parent: ViewGroup, inflate: (LayoutInflater, ViewGroup, Boolean) -> VB) : this(inflate(LayoutInflater.from(parent.context), parent, false))
}

inline fun <VB: ViewBinding> Dialog.binding(crossinline inflater: (LayoutInflater) -> VB) = lazy(LazyThreadSafetyMode.NONE) {
    inflater(layoutInflater).also {
        setContentView(it.root)
    }
}

inline fun <VB: ViewBinding> AppCompatActivity.popupWindow(
    crossinline inflate: (LayoutInflater) -> VB,
    width: Int = ViewGroup.LayoutParams.WRAP_CONTENT,
    height: Int = ViewGroup.LayoutParams.WRAP_CONTENT,
    focusable: Boolean = false, crossinline block: VB.() -> Unit) = lazy(LazyThreadSafetyMode.NONE) {
    PopupWindow(inflate(layoutInflater).apply(block).root, width, height, focusable)
}

inline fun <VB: ViewBinding> Fragment.popupWindow(
    crossinline inflate: (LayoutInflater) -> VB,
    width: Int = ViewGroup.LayoutParams.WRAP_CONTENT,
    height: Int = ViewGroup.LayoutParams.WRAP_CONTENT,
    focusable: Boolean = false, crossinline block: VB.() -> Unit) = lazy(LazyThreadSafetyMode.NONE) {
    PopupWindow(inflate(layoutInflater).apply(block).root, width, height, focusable)
}

inline fun <VB: ViewBinding> Fragment.createPopupWindow(
    crossinline inflate: (LayoutInflater) -> VB,
    width: Int = ViewGroup.LayoutParams.WRAP_CONTENT,
    height: Int = ViewGroup.LayoutParams.WRAP_CONTENT,
    focusable: Boolean = false, crossinline block: VB.() -> Unit): PopupWindow {
    return PopupWindow(inflate(layoutInflater).apply(block).root, width, height, focusable)
}

inline fun <VB: ViewBinding> AppCompatActivity.createPopupWindow(
    crossinline inflate: (LayoutInflater) -> VB,
    width: Int = ViewGroup.LayoutParams.WRAP_CONTENT,
    height: Int = ViewGroup.LayoutParams.WRAP_CONTENT,
    focusable: Boolean = false, crossinline block: VB.() -> Unit): PopupWindow {
    return PopupWindow(inflate(layoutInflater).apply(block).root, width, height, focusable)
}